<template>
  <el-dialog
    :title="'选择节点'"
    :visible="showDialog"
    :close-on-click-modal="false"
    :close-on-press-escape="false"
    width="40%"
    append-to-body
    custom-class="node_dialog"
    @opened="openDialog"
    @close="handelCancel">
    <div class="dept_box_content">
      <div class="dept_serach">
        <el-form
          ref="deptForm"
          inline
          :model="formData">
          <el-form-item
            prop="deptName"
            label="部门名称:">
            <el-input
              v-model="formData.deptName"
              clearable
              placeholder="请输入部门名称" />
          </el-form-item>
          <el-form-item
            prop="deptCode"
            label="部门编码:">
            <el-input
              v-model="formData.deptCode"
              clearable
              placeholder="请输入部门编码" />
          </el-form-item>
        </el-form>
      </div>
      <div
        v-loading="load"
        element-loading-text="拼命加载中"
        element-loading-spinner="el-icon-loading"
        element-loading-background="rgba(255, 255, 255, 1)"
        class="dept_tree_box">
        <el-tree
          ref="tree"
          check-strictly
          :data="deptOptions"
          :props="defaultProps"
          :expand-on-click-node="false"
          :filter-node-method="filterNode"
          show-checkbox
          node-key="id"
          default-expand-all
          highlight-current
          @check-change="handleNodeClick">
          <span slot-scope="{ node, data }" class="custom-tree-node">
            {{ data.label }}
            <el-checkbox
              v-model="data.childFlag"
              @change="handelCheckbox(node, data)">
              包含子节点
            </el-checkbox>
          </span>
        </el-tree>
      </div>
    </div>
    <div slot="footer">
      <el-button
        @click="handelCancel">
        取 消
      </el-button>
      <el-button
        type="primary"
        @click="handelConfirm">
        确 定
      </el-button>
    </div>
  </el-dialog>
</template>

<script>
import api from '@/api/index';

export default {
  inheritAttrs: false,
  model: {
    prop: 'showDialog',
    event: 'closeDialog'
  },
  props: {
    /** 展示开关 */
    showDialog: {
      type: Boolean,
      default: false
    },
    /** 初始数据 */
    treeBeSelect: {
      type: Array,
      default: () => []
    }
  },
  data() {
    return {
      load: false,
      // 部门查询条件
      formData: {
        deptName: undefined,
        deptCode: undefined
      },
      // 部门树图
      deptOptions: [],
      // 树图结构
      defaultProps: {
        children: 'children',
        label: 'label'
      },
      hideChildren: []
    };
  },
  watch: {
    'formData.deptName'(val) {
      this.$refs.tree.filter({ str: val, type: 'name' });
    },
    'formData.deptCode'(val) {
      this.$refs.tree.filter({ str: val, type: 'code' });
    }
  },
  methods: {
    /**
     * @description: 查询部门下拉树结构
     */
    async getDeptTree() {
      this.loading = true;
      const res = await this.awaitCatch(api.deptTreeUseSelect());
      if (res.code === 0) {
        const resData = res.data;
        const flagArr = [];
        this.treeBeSelect.forEach(item => {
          if (item.childFlag) flagArr.push(item.id);
        });
        flagArr.forEach(item => {
          this.changeData(resData[0], item);
        });

        this.deptOptions = resData;

        const idArr = this.treeBeSelect.map(item => { return item.id; });
        this.$refs.tree.setCheckedKeys(idArr); // 给树节点赋值回显
      }
      this.loading = false;
    },

    /**
     * @description: 递归判断对象是否包含子节点，并存储被隐藏子项
     * @param {obj} data 节点数据
     * @param {str} selectFlag 是否选中
     */
    changeData(data, key) {
      if (data.id === key) {
        data.childFlag = true;
      }
      if (data.childFlag && data.children && data.children.length) {
        this.hideChildren[data.id] = data.children;
        data.children = [];
      }
      if (data.children && data.children.length) {
        data.children.forEach(item => {
          this.changeData(item, key);
        });
      }
    },

    /**
     * @description: 节点单击
     * @param {obj} data 节点数据
     * @param {bol} selectFlag 是否选中
     * @param {bol} childNode 是否包含子节点
     */
    handleNodeClick(data, selectFlag, childNode) {
      if (!selectFlag && data.childFlag) {
        data.childFlag = false;
        data.children = this.hideChildren[data.id];
      }
    },

    /**
     * @description: 筛选节点
     * @param {obj} strObj 输入框
     * @param {obj} data 树图数据
     */
    filterNode(strObj, data) {
      if (!strObj) return true;
      if (strObj.type === 'name') {
        return data.label.indexOf(strObj.str) !== -1;
      }
      if (strObj.type === 'code') {
        return data.id.indexOf(strObj.str) !== -1;
      }
    },

    /**
     * @description: 确定
     */
    handelConfirm() {
      const checked = this.$refs.tree.getCheckedNodes();
      const param = {
        type: 'node',
        val: checked
      };
      this.$emit('getDialogData', param);
      this.handelCancel();
    },

    /**
     * @description: 打开dialog
     */
    openDialog() {
      this.getDeptTree();
    },

    /**
     * @description: 关闭dialog
     */
    handelCancel() {
      Object.assign(this.$data, this.$options.data());
      this.$emit('closeDialog', false);
    },

    /**
     * @description: 点击自定义节点
     */
    handelCheckbox(node, data) {
      if (data.childFlag) {
        node.checked = true;
        this.hideChildren[data.id] = data.children;
        this.clearChilren(data.children);
        data.children = [];
      } else {
        node.checked = false;
        data.children = this.hideChildren[data.id];
      }
    },

    /**
     * 清除子节点状态
     */
    clearChilren(arr) {
      if (!arr || !arr.length) return;
      arr.forEach(item => {
        if (item.childFlag) item.childFlag = false;
        if (item.children) {
          this.clearChilren(item.children);
        }
      });
    }
  }
};
</script>

<style lang="scss" scoped>
.dept_box_content {
  display: inline-block;
  width: 100%;
  min-width: 260px;
  height: 430px;
  border: 1px solid #ddd;
}

.dept_serach {
  height: 60px;
  border-bottom: 1px solid #ddd;

  .el-form-item {
    margin: 10px;
  }

  .el-input {
    width: 150px;
  }
}

.dept_tree_box {
  width: 100%;
  height: calc(100% - 60px);
  padding: 10px;
  overflow: auto;
}
</style>
